/**
 * 
 */
package cn.bblocks.cacheTest.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.support.Page4Navigator;
import org.springframework.stereotype.Service;

import cn.bblocks.cacheTest.configuration.NoRepeatSubmit;
import cn.bblocks.cacheTest.model.User;
import cn.bblocks.cacheTest.model.UserBank;
import cn.bblocks.cacheTest.model.dao.UserBankMapper;
import cn.bblocks.cacheTest.service.UserBankService;
import cn.bblocks.cacheTest.suport.RandomValue;
import cn.hutool.core.util.RandomUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Administrator
 *
 */
/**
 * @author Administrator
*	redis_plus缓存 方案（方案实例：User（用户表），UserBank(用户银行卡)）：
 * 自动缓存更新方案：
 * 1、del：无需特别处理，即可确保查询最新数据(删除一条，当缓存数据List中含本条数据会导致组织失败，重新执行查询)
 * 2、update：分为两种情况，
 *    a、更新了无关字段， 比如更新了用户表中昵称，则 @CachePut(key = "#p0.id") 即可
 *    b、更新了有关字段,比如更新了 用户银行卡中得status为0（无效了），则：@CachePut(key = "#p0.id") 和 @Caching( evict = {@CacheEvict(key = "'&userId='+#userId+'*'")})
 *附：所谓无关有关，判断条件：这个字段有没有在查询条件中，比如 用户表中昵称判断为无关业务没有基于昵称得查询否则不成功，
 *   所谓有关 ，这个字段在查询条件中，比如存在我得银行卡业务查询并缓存了 @Cacheable( key = "'&userId='+#p0+'&page='+#p1.pageNumber+'&size='+#p1.pageSize")，现在更新了status=0，则影响了这个缓存结果所以判断为这个查询有关，需要清除这个缓存
 * 3、add:也是影响查询结果集合，比如我添加了一张银行卡则：	@Caching( evict = {@CacheEvict(key = "'&userId='+#p0.userId+'&*'")})
 * 4、此方案生效有几个条件
 *    a、实体 存在 @Id：用于标记属性的主键(复合主键未测试)
 *    b、key得规范：&a=1&b=2&b=3 类似这样，比如查询用户得银行卡：key = "'&userId='+#p0+'&page='+#p1.pageNumber+'&size='+#p1.pageSize"
 *    c、evict得key模糊匹配方案(存在*才为模糊匹配方案，否则为标准key方案)：&a=1&b=2&b=3&*，比如用户银行添加了银行卡则evict key：key = "'&userId='+#userId+'&*'"																									           ,@CacheEvict(key = "'&userId='+#p1+'*'")})
 */
@Data
@Slf4j
@Service
@CacheConfig(cacheNames = "UserBank") 
public class UserBankServiceImpl implements UserBankService {
	
	@Autowired
	private UserBankMapper userBankMapper;
	
	/* (non-Javadoc)
	 * @see com.wenkor.ticket.service.UserBankService#getBank(java.lang.Integer)
	 */
	@Override
	@Cacheable(key = "#id")  
	public UserBank getBank(Integer id) {
		// TODO Auto-generated method stub
		
		return userBankMapper.findById(id).orElse(null);
	}
	
	
	public UserBank getBank2(Integer id) {
		// TODO Auto-generated method stub
		
		return userBankMapper.findById(id).orElse(null);
	}

	/* (non-Javadoc)
	 * @see com.wenkor.ticket.service.UserBankService#getMyBanks()
	 */
	@Override
	@Cacheable( key = "'&userId='+#p0")
	public List<UserBank> getMyBanks(Integer userId) {
		// TODO Auto-generated method stub
		return userBankMapper.findByIdcardseqnoAndStatusOrderByIdDesc(userId,1);
	}
	
	@Cacheable( key = "'&userId='+#p0+'&page='+#p1.pageNumber+'&size='+#p1.pageSize")
	public Page4Navigator<UserBank> getMyPageBanks(Integer userId
			, Pageable pageable) {
		// TODO Auto-generated method stub
		Page<UserBank> page = userBankMapper.findUserBanksByPage(userId,pageable);
		
		return new Page4Navigator(page);
	}

	/* (non-Javadoc)
	 * @see com.wenkor.ticket.service.UserBankService#add()
	 */
	/**
	 *新增操作1+1种方式(演示得是最精准得方案)：
	 *1、更新核心查询得 @Caching( evict = {@CacheEvict(key = "'&userId='+#p0.idcardseqno+'*'")})
	 *2、不知道受影响面 全部清除@CacheEvict(allEntries=true)）
	 */
	//@CachePut(key = "#p0.id")
	@Caching( evict = {@CacheEvict(key = "'&userId='+#p0.idcardseqno+'&*'")})
	//@CacheEvict(allEntries=true)
	public UserBank add(UserBank onebank) {
		// TODO Auto-generated method stub
		 userBankMapper.saveAndFlush(onebank);
		 return onebank;
	}

	//@NoRepeatSubmit(key="#onebank.id")
	@CachePut(key = "#p0.id")  
	//@CacheEvict(key = "#p0.id") 
	public UserBank update(UserBank onebank) {
		onebank.setUpdateTime(new Date());
		onebank = userBankMapper.saveAndFlush(onebank);
		
		//onebank.setVersion(onebank.getVersion()+1);
		return onebank;
	}

	/**
	 *更新操作2+1种方式(演示得是最精准得方案)：
	 *1、无关查询更新（@CachePut(key = "#result.id") 或者 @CacheEvict(key = "#id")  最好前者）
	 *2、和核心查询有关得（比如本处修改了 idcardseqno）
	 *3、不知道哪些查询受影响（@CacheEvict(allEntries=true)）
	 */
	@CachePut(key = "#p0.id")
	@Caching( evict = {@CacheEvict(key = "'&userId='+#p0.idcardseqno+'*'")
		,@CacheEvict(key = "'&userId='+#p1+'*'")})
	public UserBank update(UserBank onebank,Integer tagetUserId) {
		// TODO Auto-generated method stub
		if(tagetUserId != null)
			onebank.setIdcardseqno(tagetUserId);
		onebank.setUpdateTime(new Date());
		onebank = userBankMapper.saveAndFlush(onebank);
		return onebank;
	}
	
	
	
	@CachePut(key = "#p0.id")  
	@Caching( evict = {@CacheEvict(key = "'&userId='+#p0.idcardseqno+'*'")})
	public UserBank update2(UserBank onebank) {
		onebank.setUpdateTime(new Date());
		onebank.setStatus(0);
		onebank = userBankMapper.saveAndFlush(onebank);
		return onebank;
	}

	/* (non-Javadoc)
	 * @see com.wenkor.ticket.service.UserBankService#deleteByPrimaryKey(java.lang.Integer)
	 */
	/**
	 *常见得删除有2+1种操作（逻辑删除和 update类似），
	 *1、逻辑删除（@CacheEvict(key = "#p0.idcardseqno") or 清除和本条数据相关缓存  @CacheEvict(key = "'&userId='+#p0.idcardseqno+'*'")  ）、
	 *2、物理删除（@CacheEvict(key = "#p0.idcardseqno") ）
	 *3、不明确影响面，则全删@CacheEvict(allEntries=true)
	 */
	//
	@CachePut(key = "#p0.id") 
	@CacheEvict(key = "'&userId='+#p0.idcardseqno+'&=*'")
//	@CacheEvict(allEntries=true)
	public UserBank deleteByPrimaryKey(UserBank onebank) {
		// TODO Auto-generated method stub
		//userBankMapper.deleteById(id);
		
//		Optional<UserBank> bank = userBankMapper.findById(onebank.getId());
//		if(bank.isPresent()) {
		onebank.setStatus(0);
		onebank = userBankMapper.saveAndFlush(onebank);
//		}
			//onebank.setVersion(onebank.getVersion()+1);
		return onebank;
	}
	
	//物理删除
	@CacheEvict(key = "#p0") 
	public void deleteByPrimaryKey(Integer id) {
		// TODO Auto-generated method stub
		userBankMapper.deleteById(id);
	}
	
	
	public void add(List<UserBank> banks) {
		// TODO Auto-generated method stub
		 userBankMapper.saveAll(banks);
	}
	
	 public void initUserBanks(User user) {
		 
		 int bankNum = RandomUtil.randomInt(100);//最多100个把
		 
		 List<UserBank> banks = new ArrayList();
		 for(int i=0;i<bankNum;i++) {
			 UserBank onebank = new UserBank();
				onebank.setIdcardseqno(user.getId());
				onebank.setCreateTime(new Date());
			
				onebank.setMobile(RandomValue.getTel());
				//62266609 0168 3439
				onebank.setNum("62266609"+RandomValue.getNum(1000, 10000) + RandomValue.getNum(1000, 10000));
				onebank.setRealName(user.getName());
				
				//userBankService.add(onebank);
				banks.add(onebank);
		 }
		 
		 add(banks);
	 }

}
